class MapDragScale {
    constructor(mapAreaId, mapContainerId, options = {}) {
      
      this.mapArea = document.getElementById(mapAreaId);
      this.mapContainer = document.getElementById(mapContainerId);
      
      this.options = {
        minScale: 1,
        maxScale: 5,
        navHeight: 0,
        ...options
      };
      
      this.data = {
        scale: 1,
        x: 0,
        y: 0,
        mapAreaHeight: 0,
        isDragging: false,
        lastX: 0,
        lastY: 0,
        start: {}
      };
      
      this.bindEvents();
      
      this.calcMapAreaHeight();
      window.addEventListener('resize', () => this.calcMapAreaHeight());
    }
    
    calcMapAreaHeight() {
      this.data.mapAreaHeight = window.innerHeight - this.options.navHeight;
      this.mapArea.style.height = `${this.data.mapAreaHeight}px`;
    }
    
    getDistance(touch1, touch2) {
      const x1 = (typeof touch1.clientX === 'number') ? touch1.clientX : touch1.x;
      const y1 = (typeof touch1.clientY === 'number') ? touch1.clientY : touch1.y;
      const x2 = (typeof touch2.clientX === 'number') ? touch2.clientX : touch2.x;
      const y2 = (typeof touch2.clientY === 'number') ? touch2.clientY : touch2.y;
      const dx = x2 - x1;
      const dy = y2 - y1;
      return Math.sqrt(dx * dx + dy * dy);
    }
    
    clampPosition() {
      const areaWidth = this.mapArea.clientWidth;
      const areaHeight = this.mapArea.clientHeight;
      const contentWidth = this.mapContainer.offsetWidth * this.data.scale;
      const contentHeight = this.mapContainer.offsetHeight * this.data.scale;

      const minX = areaWidth - contentWidth;
      const minY = areaHeight - contentHeight;

      if (!Number.isFinite(this.data.x)) this.data.x = 0;
      if (!Number.isFinite(this.data.y)) this.data.y = 0;

      this.data.x = Math.min(0, Math.max(minX, this.data.x));
      this.data.y = Math.min(0, Math.max(minY, this.data.y));
    }

    updateMapTransform() {
      this.clampPosition();
      this.mapContainer.style.transform = `translate(${this.data.x}px, ${this.data.y}px) scale(${this.data.scale})`;
    }
    
    handleDragStart = (e) => {
      if (e.touches && e.touches.length > 1) return;
      
      this.data.isDragging = true;
      this.data.lastX = e.clientX || e.touches[0].clientX;
      this.data.lastY = e.clientY || e.touches[0].clientY;
    }
    
    handleDragging = (e) => {
      if (!this.data.isDragging) return;
      e.preventDefault();
      
      const currentX = e.clientX || e.touches[0].clientX;
      const currentY = e.clientY || e.touches[0].clientY;
      
      const deltaX = currentX - this.data.lastX;
      const deltaY = currentY - this.data.lastY;
      
      this.data.x += deltaX;
      this.data.y += deltaY;
      
      this.data.lastX = currentX;
      this.data.lastY = currentY;
      
      this.updateMapTransform();
    }
    
    handleDragEnd = () => {
      this.data.isDragging = false;
      this.data.start = {};
    }
    
    handleScale = (e) => {
      e.preventDefault();
      
      if (e.touches.length === 2) {
        const touch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY };
        const touch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY };
        
        if (!this.data.start.scale) {
          this.data.start.scale = this.getDistance(touch1, touch2);
          this.data.start.originScale = this.data.scale;
          return;
        }
        
        const current = this.getDistance(touch1, touch2);
        let scale = (current / this.data.start.scale) * this.data.start.originScale;
        scale = Math.min(this.options.maxScale, Math.max(this.options.minScale, scale));
        this.data.scale = scale;
        this.updateMapTransform();
      }
    }
    
    bindEvents() {
      this.mapContainer.addEventListener('mousedown', this.handleDragStart);
      document.addEventListener('mousemove', this.handleDragging);
      document.addEventListener('mouseup', this.handleDragEnd);
      document.addEventListener('mouseleave', this.handleDragEnd);
      
      this.mapContainer.addEventListener('touchstart', this.handleDragStart);
      document.addEventListener('touchmove', this.handleDragging, { passive: false });
      document.addEventListener('touchend', this.handleDragEnd);
      
      document.addEventListener('touchmove', this.handleScale, { passive: false });

      // 按高度铺满时自适应容器尺寸，确保边界计算正确
      if (this.mapContainer.getAttribute('data-fit') === 'height') {
        const img = this.mapContainer.querySelector('img');
        const applySize = () => {
          const areaHeight = this.mapArea.clientHeight;
          if (img && img.naturalWidth && img.naturalHeight && areaHeight > 0) {
            const targetWidth = (img.naturalWidth / img.naturalHeight) * areaHeight;
            this.mapContainer.style.height = areaHeight + 'px';
            this.mapContainer.style.width = targetWidth + 'px';
            this.updateMapTransform();
          }
        };
        if (img) {
          if (img.complete) {
            applySize();
          } else {
            img.addEventListener('load', applySize, { once: true });
          }
        }
        window.addEventListener('resize', applySize);
      }

      // 按宽度铺满时自适应容器尺寸
      if (this.mapContainer.getAttribute('data-fit') === 'width') {
        const img = this.mapContainer.querySelector('img');
        const applySize = () => {
          const areaWidth = this.mapArea.clientWidth;
          if (img && img.naturalWidth && img.naturalHeight && areaWidth > 0) {
            const targetHeight = (img.naturalHeight / img.naturalWidth) * areaWidth;
            this.mapContainer.style.width = areaWidth + 'px';
            this.mapContainer.style.height = targetHeight + 'px';
            this.updateMapTransform();
          }
        };
        if (img) {
          if (img.complete) {
            applySize();
          } else {
            img.addEventListener('load', applySize, { once: true });
          }
        }
        window.addEventListener('resize', applySize);
      }

      this.updateMapTransform();
    }
  }

// 全局导出
window.MapDragScale = MapDragScale;